{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nibpbUnTsxTd"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "tXAbWHtqs1Y2"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HTgMAvQq-PU_"
      },
      "source": [
        "# 비정형 텐서\n",
        "\n",
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/guide/ragged_tensor\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />TensorFlow.org에서 보기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/guide/ragged_tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />구글 코랩(Colab)에서 실행하기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/guide/ragged_tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />깃허브(GitHub)에서 소스 보기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/guide/ragged_tensor.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />노트북 다운로드</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-agGVYp_4GWZ"
      },
      "source": [
        "Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도\n",
        "불구하고 [공식 영문 문서](https://www.tensorflow.org/?hl=en)의 내용과 일치하지 않을 수 있습니다.\n",
        "이 번역에 개선할 부분이 있다면\n",
        "[tensorflow/docs-l10n](https://github.com/tensorflow/docs-l10n/) 깃헙 저장소로 풀 리퀘스트를 보내주시기 바랍니다.\n",
        "문서 번역이나 리뷰에 참여하려면\n",
        "[docs-ko@tensorflow.org](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ko)로\n",
        "메일을 보내주시기 바랍니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cDIUjj07-rQg"
      },
      "source": [
        "## 설정"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KKvdSorS-pDD"
      },
      "outputs": [],
      "source": [
        "import math\n",
        "import tensorflow as tf"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pxi0m_yf-te5"
      },
      "source": [
        "## 개요\n",
        "\n",
        "데이터는 다양한 형태로 제공됩니다; 텐서도 마찬가지입니다.\n",
        "*비정형 텐서*는 중첩 가변 길이 목록에 해당하는 텐서플로입니다.\n",
        "다음을 포함하여 균일하지 않은 모양으로 데이터를 쉽게 저장하고 처리할 수 있습니다:\n",
        "\n",
        "\n",
        "*   일련의 영화의 배우들과 같은 가변 길이 기능\n",
        "*   문장이나 비디오 클립과 같은 가변 길이 순차적 입력의 배치\n",
        "    \n",
        "*   절, 단락, 문장 및 단어로 세분화된 텍스트 문서와 같은 계층적 입력\n",
        "    \n",
        "*   프로토콜 버퍼와 같은 구조화된 입력의 개별 필드\n",
        "\n",
        "### 비정형 텐서로 할 수 있는 일\n",
        "\n",
        "비정형 텐서는 수학 연산 (예 : `tf.add` 및 `tf.reduce_mean`), \n",
        "배열 연산 (예 : `tf.concat` 및 `tf.tile`),\n",
        "문자열 조작 작업 (예 : `tf.substr`)을 포함하여 수백 가지 이상의 텐서플로 연산에서 지원됩니다\n",
        ":\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vGmJGSf_-PVB"
      },
      "outputs": [],
      "source": [
        "digits = tf.ragged.constant([[3, 1, 4, 1], [], [5, 9, 2], [6], []])\n",
        "words = tf.ragged.constant([[\"So\", \"long\"], [\"thanks\", \"for\", \"all\", \"the\", \"fish\"]])\n",
        "print(tf.add(digits, 3))\n",
        "print(tf.reduce_mean(digits, axis=1))\n",
        "print(tf.concat([digits, [[5, 3]]], axis=0))\n",
        "print(tf.tile(digits, [1, 2]))\n",
        "print(tf.strings.substr(words, 0, 2))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Pt-5OIc8-PVG"
      },
      "source": [
        "팩토리 메서드, 변환 메서드 및 값 매핑 연산을 포함하여 비정형 텐서에 \n",
        "고유한 여러 메서드 및 연산도 있습니다.\n",
        "\n",
        "지원되는 작업 목록은 `tf.ragged` 패키지 문서를 참조하십시오.\n",
        "\n",
        "\n",
        "일반 텐서와 마찬가지로, Python 스타일 인덱싱을 사용하여 비정형 텐서의 특정 부분에 접근할 수 있습니다.\n",
        "자세한 내용은 아래\n",
        "**인덱싱** 절을 참조하십시오."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "n8YMKXpI-PVH"
      },
      "outputs": [],
      "source": [
        "print(digits[0])       # 첫 번째 행"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Awi8i9q5_DuX"
      },
      "outputs": [],
      "source": [
        "print(digits[:, :2])   # 각 행의 처음 두 값"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sXgQtTcgHHMR"
      },
      "outputs": [],
      "source": [
        "print(digits[:, -2:])  # 각 행의 마지막 두 값"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6FU5T_-8-PVK"
      },
      "source": [
        "일반 텐서와 마찬가지로, 파이썬 산술 및 비교 연산자를 사용하여 요소 별 연산을 수행할 수 있습니다.\n",
        "자세한 내용은 아래의\n",
        "**오버로드된 연산자** 절을 참조하십시오."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2tdUEtb7-PVL"
      },
      "outputs": [],
      "source": [
        "print(digits + 3)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "X-bxG0nc_Nmf"
      },
      "outputs": [],
      "source": [
        "print(digits + tf.ragged.constant([[1, 2, 3, 4], [], [5, 6, 7], [8], []]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2tsw8mN0ESIT"
      },
      "source": [
        "`RaggedTensor`의 값으로 요소 별 변환을 수행해야하는 경우, 함수와 하나 이상의 매개변수를 갖는 `tf.ragged.map_flat_values`를 사용할 수 있고, `RaggedTensor`의 값을 변환할 때 적용할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pvt5URbdEt-D"
      },
      "outputs": [],
      "source": [
        "times_two_plus_one = lambda x: x * 2 + 1\n",
        "print(tf.ragged.map_flat_values(times_two_plus_one, digits))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7M5RHOgp-PVN"
      },
      "source": [
        "### 비정형 텐서 생성하기\n",
        "\n",
        "비정형 텐서를 생성하는 가장 간단한 방법은 \n",
        "`tf.ragged.constant`를 사용하는 것입니다. `tf.ragged.constant`는 주어진 중첩된 Python 목록에 해당하는 `RaggedTensor`를\n",
        "빌드 합니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yhgKMozw-PVP"
      },
      "outputs": [],
      "source": [
        "sentences = tf.ragged.constant([\n",
        "    [\"Let's\", \"build\", \"some\", \"ragged\", \"tensors\", \"!\"],\n",
        "    [\"We\", \"can\", \"use\", \"tf.ragged.constant\", \".\"]])\n",
        "print(sentences)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "TW1g7eE2ee8M"
      },
      "outputs": [],
      "source": [
        "paragraphs = tf.ragged.constant([\n",
        "    [['I', 'have', 'a', 'cat'], ['His', 'name', 'is', 'Mat']],\n",
        "    [['Do', 'you', 'want', 'to', 'come', 'visit'], [\"I'm\", 'free', 'tomorrow']],\n",
        "])\n",
        "print(paragraphs)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SPLn5xHn-PVR"
      },
      "source": [
        "비정형 텐서는 `tf.RaggedTensor.from_value_rowids`, `tf.RaggedTensor.from_row_lengths` 및 `tf.RaggedTensor.from_row_splits`와 \n",
        "`tf.RaggedTensor.from_row_splits`와 같은 팩토리 클래스 메서드를 사용하여\n",
        "플랫 *values* 텐서와 *행 분할* 텐서를 쌍을 지어 해당 값을 행으로 분할하는 방법을 표시하는 방식으로도 생성할 수 있습니다.\n",
        "\n",
        "\n",
        "\n",
        "#### `tf.RaggedTensor.from_value_rowids`\n",
        "각 값이 속하는 행을 알고 있으면 `value_rowids` 행 분할 텐서를 사용하여 `RaggedTensor`를 빌드할 수 있습니다:\n",
        "\n",
        "![value_rowids](https://www.tensorflow.org/images/ragged_tensors/value_rowids.png)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SEvcPUcl-PVS"
      },
      "outputs": [],
      "source": [
        "print(tf.RaggedTensor.from_value_rowids(\n",
        "    values=[3, 1, 4, 1, 5, 9, 2, 6],\n",
        "    value_rowids=[0, 0, 0, 0, 2, 2, 2, 3]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RBQh8sYc-PVV"
      },
      "source": [
        "#### `tf.RaggedTensor.from_row_lengths`\n",
        "\n",
        "각 행의 길이를 알고 있으면 `row_lengths` 행 분할 텐서를 사용할 수 있습니다:\n",
        "\n",
        "![row_lengths](https://www.tensorflow.org/images/ragged_tensors/row_lengths.png)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LBY81WXl-PVW"
      },
      "outputs": [],
      "source": [
        "print(tf.RaggedTensor.from_row_lengths(\n",
        "    values=[3, 1, 4, 1, 5, 9, 2, 6],\n",
        "    row_lengths=[4, 0, 3, 1]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8p5V8_Iu-PVa"
      },
      "source": [
        "#### `tf.RaggedTensor.from_row_splits`\n",
        "\n",
        "각 행의 시작과 끝 인덱스를 알고 있다면 `row_splits` 행 분할 텐서를 사용할 수 있습니다:\n",
        "\n",
        "![row_splits](https://www.tensorflow.org/images/ragged_tensors/row_splits.png)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FwizuqZI-PVb"
      },
      "outputs": [],
      "source": [
        "print(tf.RaggedTensor.from_row_splits(\n",
        "    values=[3, 1, 4, 1, 5, 9, 2, 6],\n",
        "    row_splits=[0, 4, 4, 7, 8]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "E-9imo8DhwuA"
      },
      "source": [
        "팩토리 메서드의 전체 목록은 `tf.RaggedTensor` 클래스 문서를 참조하십시오."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YQAOsT1_-PVg"
      },
      "source": [
        "### 비정형 텐서에 저장할 수 있는 것\n",
        "\n",
        "일반 `텐서`와 마찬가지로, `RaggedTensor`의 값은 모두 같은 유형이어야 합니다;\n",
        "값은 모두 동일한 중첩 깊이 (텐서의 *랭크*)에\n",
        "있어야 합니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SqbPBd_w-PVi"
      },
      "outputs": [],
      "source": [
        "print(tf.ragged.constant([[\"Hi\"], [\"How\", \"are\", \"you\"]]))  # 좋음: 유형=문자열, 랭크=2"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "83ZCSJnQAWAf"
      },
      "outputs": [],
      "source": [
        "print(tf.ragged.constant([[[1, 2], [3]], [[4, 5]]]))        # 좋음: 유형=32비트정수, 랭크=3"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ewA3cISdDfmP"
      },
      "outputs": [],
      "source": [
        "try:\n",
        "  tf.ragged.constant([[\"one\", \"two\"], [3, 4]])              # 안좋음: 다수의 유형\n",
        "except ValueError as exception:\n",
        "  print(exception)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EOWIlVidDl-n"
      },
      "outputs": [],
      "source": [
        "try:\n",
        "  tf.ragged.constant([\"A\", [\"B\", \"C\"]])                     # 안좋음: 다중첩 깊이\n",
        "except ValueError as exception:\n",
        "  print(exception)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nhHMFhSp-PVq"
      },
      "source": [
        "### 사용 예시\n",
        "\n",
        "다음 예제는 `RaggedTensor`를 사용하여 각 문장의 시작과 끝에 특수 마커를 사용하여\n",
        "가변 길이 쿼리 배치에 대한 유니그램 및 바이그램 임베딩을 생성하고 결합하는 방법을 보여줍니다.\n",
        "이 예제에서 사용된 작업에 대한 자세한 내용은\n",
        "`tf.ragged` 패키지 설명서를 참조하십시오."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZBs_V7e--PVr"
      },
      "outputs": [],
      "source": [
        "queries = tf.ragged.constant([['Who', 'is', 'Dan', 'Smith'],\n",
        "                              ['Pause'],\n",
        "                              ['Will', 'it', 'rain', 'later', 'today']])\n",
        "\n",
        "# 임베딩 테이블 만들기\n",
        "num_buckets = 1024\n",
        "embedding_size = 4\n",
        "embedding_table = tf.Variable(\n",
        "    tf.random.truncated_normal([num_buckets, embedding_size],\n",
        "                       stddev=1.0 / math.sqrt(embedding_size)))\n",
        "\n",
        "# 각 단어에 대한 임베딩 찾기\n",
        "word_buckets = tf.strings.to_hash_bucket_fast(queries, num_buckets)\n",
        "word_embeddings = tf.ragged.map_flat_values(\n",
        "    tf.nn.embedding_lookup, embedding_table, word_buckets)                  # ①\n",
        "\n",
        "# 각 문장의 시작과 끝에 마커 추가하기\n",
        "marker = tf.fill([queries.nrows(), 1], '#')\n",
        "padded = tf.concat([marker, queries, marker], axis=1)                       # ②\n",
        "\n",
        "# 바이그램 빌드 & 임베딩 찾기\n",
        "bigrams = tf.strings.join([padded[:, :-1],\n",
        "                               padded[:, 1:]],\n",
        "                              separator='+')                                # ③\n",
        "\n",
        "bigram_buckets = tf.strings.to_hash_bucket_fast(bigrams, num_buckets)\n",
        "bigram_embeddings = tf.ragged.map_flat_values(\n",
        "    tf.nn.embedding_lookup, embedding_table, bigram_buckets)                # ④\n",
        "\n",
        "# 각 문장의 평균 임베딩 찾기\n",
        "all_embeddings = tf.concat([word_embeddings, bigram_embeddings], axis=1)    # ⑤\n",
        "avg_embedding = tf.reduce_mean(all_embeddings, axis=1)                      # ⑥\n",
        "print(avg_embedding)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Y_lE_LAVcWQH"
      },
      "source": [
        "![ragged_example](https://www.tensorflow.org/images/ragged_tensors/ragged_example.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "An_k0pX1-PVt"
      },
      "source": [
        "## 비정형 텐서: 정의\n",
        "\n",
        "### 비정형 및 정형 차원\n",
        "\n",
        "*비정형 텐서*는 슬라이스의 길이가 다를 수 있는 하나 이상의 *비정형 크기*를 갖는 텐서입니다.\n",
        "예를 들어, \n",
        "`rt=[[3, 1, 4, 1], [], [5, 9, 2], [6], []]` 의 내부 (열) 크기는 \n",
        "열 슬라이스(`rt[0, :]`, ..., `rt[4, :]`)의 길이가 다르기 때문에 비정형입니다.\n",
        "부분의 길이가 모두 같은 차원을 *정형차원*이라고 합니다.\n",
        "\n",
        "비정형 텐서의 가장 바깥 쪽 차원은 단일 슬라이스로 구성되므로 슬라이스의 길이가\n",
        "다를 가능성이 없으므로 항상 균일합니다.\n",
        "비정형 텐서는 균일한 가장 바깥 쪽 차원에 더하여 균일한 내부 차원을 가질 수도 있습니다.\n",
        "예를 들어, `[num_sentences, (num_words), embedding_size]` 형태의 비정형 텐서를 사용하여 \n",
        "각 단어에 대한 단어 임베딩을 일련의 문장으로 저장할 수 있습니다.\n",
        "여기서 `(num_words)`의 괄호는 차원이 비정형임을 나타냅니다.\n",
        "\n",
        "![sent_word_embed](https://www.tensorflow.org/images/ragged_tensors/sent_word_embed.png)\n",
        "\n",
        "비정형 텐서는 다수의 비정형 차원을 가질 수 있습니다. 예를 들어\n",
        "모양이 `[num_documents, (num_paragraphs), (num_sentences), (num_words)]` 인\n",
        " 텐서를 사용하여 일련의 구조화된 텍스트 문서를 저장할 수 있습니다.\n",
        " (여기서 괄호는 비정형 차원임을 나타냅니다.)\n",
        "\n",
        "#### 비정형 텐서 형태 제한\n",
        "\n",
        "비정형 텐서의 형태는 다음과 같은 형식으로 제한됩니다:\n",
        "\n",
        "*   단일 정형 차원\n",
        "*   하나 이상의 비정형 차원\n",
        "*   0 또는 그 이상의 정형 차원\n",
        "\n",
        "참고: 이러한 제한은 현재 구현의 결과이며\n",
        "향후 완화될 수 있습니다.\n",
        "\n",
        "### 랭크 및 비정형 랭크\n",
        "\n",
        "비정형 텐서의 총 차원 수를 ***랭크***라고 하고,\n",
        "비정형 텐서의 비정형 차원 수를 ***비정형랭크***라고 합니다. 그래프 실행 모드 (즉, 비 즉시 실행(non-eager) 모드)에서, 텐서의 비정형 랭크는\n",
        "생성 시 고정됩니다: 비정형 랭크는 런타임 값에 의존할 수 없으며 다른 세션 실행에 따라\n",
        "동적으로 변할 수 없습니다.\n",
        "***잠재적으로 비정형인 텐서***는\n",
        "`tf.Tensor` 또는 `tf.RaggedTensor` 일 수 있는 값입니다.\n",
        "`tf.Tensor`의 비정형 랭크는 0으로 정의됩니다.\n",
        "\n",
        "### 비정형 텐서 형태\n",
        "\n",
        "비정형 텐서의 형태를 설명할 때, 비정형 차원은 괄호로 묶어 표시됩니다.\n",
        "예를 들어, 위에서 살펴본 것처럼 일련의 문장에서 각 단어에 대한 단어 임베딩을 저장하는\n",
        "3차원 비정형텐서의 형태는\n",
        "`[num_sentences, (num_words), embedding_size]`로 나타낼 수 있습니다.\n",
        "`RaggedTensor.shape` 프로퍼티는 비정형 텐서에 대해 크기가 없는 비정형 차원인 `tf.TensorShape`를 반환합니다:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "M2Wzx4JEIvmb"
      },
      "outputs": [],
      "source": [
        "tf.ragged.constant([[\"Hi\"], [\"How\", \"are\", \"you\"]]).shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G9tfJOeFlijE"
      },
      "source": [
        "`tf.RaggedTensor.bounding_shape` 메서드를 사용하여 지정된\n",
        "`RaggedTensor`에 대한 빈틈이 없는 경계 형태를 찾을 수 있습니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5DHaqXHxlWi0"
      },
      "outputs": [],
      "source": [
        "print(tf.ragged.constant([[\"Hi\"], [\"How\", \"are\", \"you\"]]).bounding_shape())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V8e7x95UcLS6"
      },
      "source": [
        "## 비정형 vs 희소 텐서\n",
        "\n",
        "비정형텐서는 희소 텐서의 유형이 *아니라*\n",
        "불규칙한 형태의 밀집 텐서로 간주되어야 합니다.\n",
        "\n",
        "예를 들어, 비정형 vs 희소 텐서에 대해 `concat`,\n",
        "`stack` 및 `tile`과 같은 배열 연산이 어떻게 정의되는지 고려하십시오.\n",
        "비정형 텐서들을 연결하면 각 행을 결합하여 단일 행을 형성합니다:\n",
        "\n",
        "![ragged_concat](https://www.tensorflow.org/images/ragged_tensors/ragged_concat.png)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ush7IGUWLXIn"
      },
      "outputs": [],
      "source": [
        "ragged_x = tf.ragged.constant([[\"John\"], [\"a\", \"big\", \"dog\"], [\"my\", \"cat\"]])\n",
        "ragged_y = tf.ragged.constant([[\"fell\", \"asleep\"], [\"barked\"], [\"is\", \"fuzzy\"]])\n",
        "print(tf.concat([ragged_x, ragged_y], axis=1))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pvQzZG8zMoWa"
      },
      "source": [
        "그러나 희소 텐서를 연결하는 것은 다음 예에 표시된 것처럼\n",
        " 해당 밀집 텐서를 연결하는 것과 같습니다. (여기서 Ø는 누락된 값을 나타냅니다.):\n",
        "\n",
        "![희소 텐서 합치기](https://www.tensorflow.org/images/ragged_tensors/sparse_concat.png)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eTIhGayQL0gI"
      },
      "outputs": [],
      "source": [
        "sparse_x = ragged_x.to_sparse()\n",
        "sparse_y = ragged_y.to_sparse()\n",
        "sparse_result = tf.sparse.concat(sp_inputs=[sparse_x, sparse_y], axis=1)\n",
        "print(tf.sparse.to_dense(sparse_result, ''))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Vl8eQN8pMuYx"
      },
      "source": [
        "이 구별이 중요한 이유의 다른 예를 보려면,\n",
        "`tf.reduce_mean`과 같은 연산에 대한 “각 행의 평균값”의 정의를 고려하십시오.\n",
        "비정형 텐서의 경우, 행의 평균값은 행 값을 행 너비로 나눈 값의 합입니다.\n",
        "그러나 희소 텐서의 경우 행의 평균값은\n",
        "행 값의 합계롤 희소 텐서의 전체 너비(가장 긴 행의 너비 이상)로\n",
        "나눈 값입니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cRcHzS6pcHYC"
      },
      "source": [
        "## 오버로드된 연산자\n",
        "\n",
        "`RaggedTensor` 클래스는 표준 Python 산술 및 비교 연산자를 오버로드하여\n",
        "기본 요소 별 수학을 쉽게 수행할 수 있습니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "skScd37P-PVu"
      },
      "outputs": [],
      "source": [
        "x = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])\n",
        "y = tf.ragged.constant([[1, 1], [2], [3, 3, 3]])\n",
        "print(x + y)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XEGgbZHV-PVw"
      },
      "source": [
        "오버로드된 연산자는 요소 단위 계산을 수행하므로, 모든\n",
        "이진 연산에 대한 입력은 동일한 형태이거나, 동일한 형태로 브로드캐스팅 할 수 있어야 합니다.\n",
        "가장 간단한 확장의 경우, 단일 스칼라가 비정형 텐서의\n",
        "각 값과 요소 별로 결합됩니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IYybEEWc-PVx"
      },
      "outputs": [],
      "source": [
        "x = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])\n",
        "print(x + 3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "okGb9dIi-PVz"
      },
      "source": [
        "고급 사례에 대한 설명은 **브로드캐스팅** 절을\n",
        "참조하십시오.\n",
        "\n",
        "비정형 텐서는 일반 `텐서`와 동일한 연산자 세트를 오버로드합니다:단항\n",
        "연산자 `-`, `~` 및 `abs()`; 그리고 이항 연산자 `+`, `-`, `*`, `/`,\n",
        "`//`, `%`, `**`, `&`, `|`, `^`, `==`, `<`, `<=`, `>` 및 `>=`.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f2anbs6ZnFtl"
      },
      "source": [
        "## 인덱싱\n",
        "\n",
        "비정형 텐서는 다차원 인덱싱 및 슬라이싱을 포함하여 Python 스타일 인덱싱을 지원합니다.\n",
        "다음 예는 2차원 및 3차원 비정형 텐서를 사용한 비정형 텐서 인덱싱을\n",
        "보여줍니다.\n",
        "\n",
        "### 비정형 1차원으로 2차원 비정형 텐서 인덱싱"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MbSRZRDz-PV1"
      },
      "outputs": [],
      "source": [
        "queries = tf.ragged.constant(\n",
        "    [['Who', 'is', 'George', 'Washington'],\n",
        "     ['What', 'is', 'the', 'weather', 'tomorrow'],\n",
        "     ['Goodnight']])\n",
        "print(queries[1])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EFfjZV7YA3UH"
      },
      "outputs": [],
      "source": [
        "print(queries[1, 2])                # 한 단어"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VISRPQSdA3xn"
      },
      "outputs": [],
      "source": [
        "print(queries[1:])                  # 첫 번째 행을 제외한 모든 단어"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "J1PpSyKQBMng"
      },
      "outputs": [],
      "source": [
        "print(queries[:, :3])               # 각 쿼리의 처음 세 단어"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ixrhHmJBeidy"
      },
      "outputs": [],
      "source": [
        "print(queries[:, -2:])              # 각 쿼리의 마지막 두 단어"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cnOP6Vza-PV4"
      },
      "source": [
        "### 비정형 2차원으로 3차원 비정형 텐서 인덱싱"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8VbqbKcE-PV6"
      },
      "outputs": [],
      "source": [
        "rt = tf.ragged.constant([[[1, 2, 3], [4]],\n",
        "                         [[5], [], [6]],\n",
        "                         [[7]],\n",
        "                         [[8, 9], [10]]])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "f9WPVWf4grVp"
      },
      "outputs": [],
      "source": [
        "print(rt[1])                        # 두 번째 행 (2차원 비정형 텐서)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ad8FGJoABjQH"
      },
      "outputs": [],
      "source": [
        "print(rt[3, 0])                     # 네 번째 행의 첫 번째 요소 (1차원 텐서)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MPPr-a-bBjFE"
      },
      "outputs": [],
      "source": [
        "print(rt[:, 1:3])                   # 각 행의 1-3 항목 (3차원 비정형 텐서)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6SIDeoIUBi4z"
      },
      "outputs": [],
      "source": [
        "print(rt[:, -1:])                   # 각 행의 마지막 항목 (3차원 비정형 텐서)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_d3nBh1GnWvU"
      },
      "source": [
        "`RaggedTensor`는 다차원 인덱싱 및 슬라이싱을 지원하며, 한 가지 제한 사항이\n",
        "있습니다: 비정형 차원으로 인덱싱할 수 없습니다. 이 값은\n",
        "표시된 값이 일부 행에 존재할 수 있지만 다른 행에는 존재하지 않기 때문에 문제가 됩니다.\n",
        "그러한 경우, 우리가 (1) `IndexError`를 제기해야 하는지; (2)\n",
        "기본값을 사용해야 하는지; 또는 (3) 그 값을 스킵하고 시작한 것보다 적은 행을 가진 텐서를 반환해야 하는지\n",
        "에 대한 여부는 확실하지 않습니다.\n",
        "[Python의 안내 지침](https://www.python.org/dev/peps/pep-0020/)\n",
        "(\"애매한 상황에서\n",
        "추측하려고 하지 마십시오\" )에 따라, 현재 이 작업을 허용하지\n",
        "않습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IsWKETULAJbN"
      },
      "source": [
        "## 텐서 형 변환\n",
        "\n",
        "`RaggedTensor` 클래스는\n",
        "`RaggedTensor`와 `tf.Tensor` 또는 `tf.SparseTensors` 사이를 변환하는데 사용할 수 있는 메서드를 정의합니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "INnfmZGcBoU_"
      },
      "outputs": [],
      "source": [
        "ragged_sentences = tf.ragged.constant([\n",
        "    ['Hi'], ['Welcome', 'to', 'the', 'fair'], ['Have', 'fun']])\n",
        "print(ragged_sentences.to_tensor(default_value=''))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "41WAZLXNnbwH"
      },
      "outputs": [],
      "source": [
        "print(ragged_sentences.to_sparse())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-rfiyYqne8QN"
      },
      "outputs": [],
      "source": [
        "x = [[1, 3, -1, -1], [2, -1, -1, -1], [4, 5, 8, 9]]\n",
        "print(tf.RaggedTensor.from_tensor(x, padding=-1))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "S8MkYo2hfVhj"
      },
      "outputs": [],
      "source": [
        "st = tf.SparseTensor(indices=[[0, 0], [2, 0], [2, 1]],\n",
        "                     values=['a', 'b', 'c'],\n",
        "                     dense_shape=[3, 3])\n",
        "print(tf.RaggedTensor.from_sparse(st))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qx025sNMkAHH"
      },
      "source": [
        "## 비정형 텐서 평가\n",
        "\n",
        "### 즉시 실행\n",
        "\n",
        "즉시 실행 모드에서는, 비정형 텐서가 즉시 실행됩니다. 포함된 값에\n",
        "접근하려면 다음을 수행하십시오:\n",
        "\n",
        "*   비정형 텐서를 Python `목록`으로 변환하는\n",
        "    `tf.RaggedTensor.to_list()`\n",
        "    메서드를 사용하십시오."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uMm1WMkc-PV_"
      },
      "outputs": [],
      "source": [
        "rt = tf.ragged.constant([[1, 2], [3, 4, 5], [6], [], [7]])\n",
        "print(rt.to_list())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SrizmqTc-PWC"
      },
      "source": [
        "*   Python 인덱싱을 사용하십시오. 선택한 텐서 조각에 비정형 차원이 없으면,\n",
        "    `EagerTensor`로 반환됩니다. 그런 다음\n",
        "    `numpy()`메서드를 사용하여 값에 직접 접근할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HpRHhfLe-PWD"
      },
      "outputs": [],
      "source": [
        "print(rt[1].numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sNlpI2fR-PWF"
      },
      "source": [
        "*   `tf.RaggedTensor.values` 및\n",
        "    `tf.RaggedTensor.row_splits` 특성 또는\n",
        "    `tf.RaggedTensor.row_lengths()` 및\n",
        "    `tf.RaggedTensor.value_rowids()`와 같은 행 분할 메서드를 사용하여\n",
        "    비정형 텐서를 구성 요소로\n",
        "    분해하십시오."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yTckrLdB-PWG"
      },
      "outputs": [],
      "source": [
        "print(rt.values)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "B8OnG9NzCEnv"
      },
      "outputs": [],
      "source": [
        "print(rt.row_splits)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EdljbNPq-PWS"
      },
      "source": [
        "### 브로드캐스팅\n",
        "\n",
        "브로드캐스팅은 다른 형태의 텐서가 요소 별 연산에 적합한 형태를 갖도록 만드는 프로세스입니다.\n",
        "브로드캐스팅에 대한 자세한 내용은\n",
        "다음을 참조하십시오:\n",
        "\n",
        "*   [Numpy: 브로드캐스팅](https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html)\n",
        "*   `tf.broadcast_dynamic_shape`\n",
        "*   `tf.broadcast_to`\n",
        "\n",
        "호환 가능한 형태를 갖도록 두 개의 입력 `x` 와 `y` 를 브로드캐스팅하는 기본 단계는\n",
        "다음과 같습니다:\n",
        "\n",
        "1.  `x` 와 `y` 의 차원 수가 동일하지 않은 경우, 외부 차원\n",
        "    (크기 1)을 차원 수가 동일해질 때까지 추가합니다 .\n",
        "\n",
        "2.  `x` 와 `y` 의 크기가 다른 각 차원에 대해:\n",
        "\n",
        "    *   차원 `d`에 `x` 또는 `y`의 크기가 `1` 이면, 다른 입력의 크기와 일치하도록\n",
        "        차원 `d`에서 값을 반복하십시오.\n",
        "\n",
        "    *   그렇지 않으면 예외가 발생합니다 (`x` 와 `y` 는 브로드캐스트와 호환되지\n",
        "        않습니다)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-S2hOUWx-PWU"
      },
      "source": [
        "정형 차원에서 텐서의 크기가 단일 숫자 (해당 차원에서\n",
        "슬라이스 크기)인 경우; 그리고 비정형 차원에서 텐서의 크기가 슬라이스 길이의 목록인 경우\n",
        "(해당 차원의 모든 슬라이스에 대해).\n",
        "\n",
        "#### 브로드캐스팅 예제"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0n095XdR-PWU"
      },
      "outputs": [],
      "source": [
        "# x       (2D ragged):  2 x (num_rows)\n",
        "# y       (scalar)\n",
        "# 결과     (2D ragged):  2 x (num_rows)\n",
        "x = tf.ragged.constant([[1, 2], [3]])\n",
        "y = 3\n",
        "print(x + y)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0SVYk5AP-PWW"
      },
      "outputs": [],
      "source": [
        "# x         (2d ragged):  3 x (num_rows)\n",
        "# y         (2d tensor):  3 x          1\n",
        "# 결과       (2d ragged):  3 x (num_rows)\n",
        "x = tf.ragged.constant(\n",
        "   [[10, 87, 12],\n",
        "    [19, 53],\n",
        "    [12, 32]])\n",
        "y = [[1000], [2000], [3000]]\n",
        "print(x + y)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MsfBMD80s8Ux"
      },
      "outputs": [],
      "source": [
        "# x      (3d ragged):  2 x (r1) x 2\n",
        "# y      (2d ragged):         1 x 1\n",
        "# 결과    (3d ragged):  2 x (r1) x 2\n",
        "x = tf.ragged.constant(\n",
        "    [[[1, 2], [3, 4], [5, 6]],\n",
        "     [[7, 8]]],\n",
        "    ragged_rank=1)\n",
        "y = tf.constant([[10]])\n",
        "print(x + y)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rEj5QVfnva0t"
      },
      "outputs": [],
      "source": [
        "# x      (3d ragged):  2 x (r1) x (r2) x 1\n",
        "# y      (1d tensor):                    3\n",
        "# 결과    (3d ragged):  2 x (r1) x (r2) x 3\n",
        "x = tf.ragged.constant(\n",
        "    [\n",
        "        [\n",
        "            [[1], [2]],\n",
        "            [],\n",
        "            [[3]],\n",
        "            [[4]],\n",
        "        ],\n",
        "        [\n",
        "            [[5], [6]],\n",
        "            [[7]]\n",
        "        ]\n",
        "    ],\n",
        "    ragged_rank=2)\n",
        "y = tf.constant([10, 20, 30])\n",
        "print(x + y)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uennZ64Aqftb"
      },
      "source": [
        "브로드캐스트 하지 않는 형태의 예는 다음과 같습니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UpI0FlfL4Eim"
      },
      "outputs": [],
      "source": [
        "# x      (2d ragged): 3 x (r1)\n",
        "# y      (2d tensor): 3 x    4  # 뒤의 차원은 일치하지 않습니다.\n",
        "x = tf.ragged.constant([[1, 2], [3, 4, 5, 6], [7]])\n",
        "y = tf.constant([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])\n",
        "try:\n",
        "  x + y\n",
        "except tf.errors.InvalidArgumentError as exception:\n",
        "  print(exception)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qGq1zOT4zMoc"
      },
      "outputs": [],
      "source": [
        "# x      (2d ragged): 3 x (r1)\n",
        "# y      (2d ragged): 3 x (r2)  # 비정형 차원은 일치하지 않습니다.\n",
        "x = tf.ragged.constant([[1, 2, 3], [4], [5, 6]])\n",
        "y = tf.ragged.constant([[10, 20], [30, 40], [50]])\n",
        "try:\n",
        "  x + y\n",
        "except tf.errors.InvalidArgumentError as exception:\n",
        "  print(exception)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "CvLae5vMqeji"
      },
      "outputs": [],
      "source": [
        "# x      (3d ragged): 3 x (r1) x 2\n",
        "# y      (3d ragged): 3 x (r1) x 3  # 뒤의 차원은 일치하지 않습니다.\n",
        "x = tf.ragged.constant([[[1, 2], [3, 4], [5, 6]],\n",
        "                        [[7, 8], [9, 10]]])\n",
        "y = tf.ragged.constant([[[1, 2, 0], [3, 4, 0], [5, 6, 0]],\n",
        "                        [[7, 8, 0], [9, 10, 0]]])\n",
        "try:\n",
        "  x + y\n",
        "except tf.errors.InvalidArgumentError as exception:\n",
        "  print(exception)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m0wQkLfV-PWa"
      },
      "source": [
        "## RaggedTensor 인코딩\n",
        "\n",
        "비정형텐서는 `RaggedTensor` 클래스를 사용하여 인코딩됩니다. 내부적으로, 각\n",
        "`RaggedTensor`는 다음으로 구성됩니다:\n",
        "\n",
        "*   가변 길이 행을 병합된 목록으로 연결하는 `values`\n",
        "    텐서\n",
        "*   병합된 값을 행으로 나누는 방법을 나타내는 `row_splits` 벡터,\n",
        "    특히, 행 `rt[i]`의 값은 슬라이스\n",
        "    `rt.values[rt.row_splits[i]:rt.row_splits[i+1]]`에 저장됩니다.\n",
        "\n",
        "![ragged_encoding](https://www.tensorflow.org/images/ragged_tensors/ragged_encoding.png)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MrLgMu0gPuo-"
      },
      "outputs": [],
      "source": [
        "rt = tf.RaggedTensor.from_row_splits(\n",
        "    values=[3, 1, 4, 1, 5, 9, 2],\n",
        "    row_splits=[0, 4, 4, 6, 7])\n",
        "print(rt)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bpB7xKoUPtU6"
      },
      "source": [
        "### 다수의 비정형 차원\n",
        "\n",
        "다수의 비정형 차원을 갖는 비정형 텐서는\n",
        "`values` 텐서에 대해 중첩된 `RaggedTensor`를 사용하여 인코딩됩니다. 중첩된 각 `RaggedTensor`는\n",
        "단일 비정형 차원을 추가합니다.\n",
        "\n",
        "![ragged_rank_2](https://www.tensorflow.org/images/ragged_tensors/ragged_rank_2.png)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yy3IGT2a-PWb"
      },
      "outputs": [],
      "source": [
        "rt = tf.RaggedTensor.from_row_splits(\n",
        "    values=tf.RaggedTensor.from_row_splits(\n",
        "        values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],\n",
        "        row_splits=[0, 3, 3, 5, 9, 10]),\n",
        "    row_splits=[0, 1, 1, 5])\n",
        "print(rt)\n",
        "print(\"형태: {}\".format(rt.shape))\n",
        "print(\"비정형 텐서의 차원 : {}\".format(rt.ragged_rank))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5HqEEDzk-PWc"
      },
      "source": [
        "팩토리 함수 `tf.RaggedTensor.from_nested_row_splits`는\n",
        "`row_splits` 텐서 목록을 제공하여 다수의 비정형 차원으로 RaggedTensor를\n",
        "직접 생성하는데 사용할 수 있습니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AKYhtFcT-PWd"
      },
      "outputs": [],
      "source": [
        "rt = tf.RaggedTensor.from_nested_row_splits(\n",
        "    flat_values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],\n",
        "    nested_row_splits=([0, 1, 1, 5], [0, 3, 3, 5, 9, 10]))\n",
        "print(rt)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uba2EnAY-PWf"
      },
      "source": [
        "### 정형한 내부 차원\n",
        "\n",
        "내부 차원이 정형한 비정형 텐서는\n",
        "`values`에 다차원 `tf.Tensor`를 사용하여 인코딩됩니다.\n",
        "\n",
        "![uniform_inner](https://www.tensorflow.org/images/ragged_tensors/uniform_inner.png)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "z2sHwHdy-PWg"
      },
      "outputs": [],
      "source": [
        "rt = tf.RaggedTensor.from_row_splits(\n",
        "    values=[[1, 3], [0, 0], [1, 3], [5, 3], [3, 3], [1, 2]],\n",
        "    row_splits=[0, 3, 4, 6])\n",
        "print(rt)\n",
        "print(\"형태: {}\".format(rt.shape))\n",
        "print(\"비정형 텐서의 차원 : {}\".format(rt.ragged_rank))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8yYaNrgX-PWh"
      },
      "source": [
        "### 대체 가능한 행 분할 방식\n",
        "\n",
        "`RaggedTensor` 클래스는 `row_splits`를 기본 메커니즘으로 사용하여\n",
        "값이 행으로 분할되는 방법에 대한 정보를 저장합니다. 그러나,\n",
        "`RaggedTensor`는 네 가지 대체 가능한 행 분할 방식을 지원하므로 데이터 형식에 따라 더 편리하게\n",
        "사용할 수 있습니다.\n",
        "내부적으로, `RaggedTensor`는 이러한 추가적인 방식을 사용하여 일부 컨텍스트에서 효율성을\n",
        "향상시킵니다.\n",
        "\n",
        "<dl>\n",
        "  <dt>행 길이</dt>\n",
        "    <dd>`row_lengths`는 `[nrows]`형태의 벡터로, 각 행의 길이를\n",
        "    지정합니다.</dd>\n",
        "\n",
        "  <dt>행 시작</dt>\n",
        "    <dd>`row_starts`는 `[nrows]`형태의 벡터로, 각 행의 시작 오프셋을\n",
        "    지정합니다. `row_splits[:-1]`와 같습니다.</dd>\n",
        "\n",
        "  <dt>행 제한</dt>\n",
        "    <dd>`row_limits`는 `[nrows]`형태의 벡터로, 각 행의 정지 오프셋을\n",
        "    지정합니다. `row_splits[1:]`와 같습니다.</dd>\n",
        "\n",
        "  <dt>행 인덱스 및 행 수</dt>\n",
        "    <dd>`value_rowids`는 `[nvals]`모양의 벡터로, 값과 일대일로 대응되며\n",
        "    각 값의 행 인덱스를 지정합니다.\n",
        "    특히, `rt[row]`행은 `value_rowids[j]==row`인 `rt.values[j]`값으로 구성됩니다.\n",
        "    \\`nrows`는\n",
        "    `RaggedTensor`의 행 수를 지정하는 정수입니다.\n",
        "    특히, `nrows`는 뒤의 빈 행을 나타내는데\n",
        "    사용됩니다.</dd>\n",
        "</dl>\n",
        "\n",
        "예를 들어, 다음과 같이 비정형 텐서는 동일합니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4TH6XoQ8-PWh"
      },
      "outputs": [],
      "source": [
        "values = [3, 1, 4, 1, 5, 9, 2, 6]\n",
        "print(tf.RaggedTensor.from_row_splits(values, row_splits=[0, 4, 4, 7, 8, 8]))\n",
        "print(tf.RaggedTensor.from_row_lengths(values, row_lengths=[4, 0, 3, 1, 0]))\n",
        "print(tf.RaggedTensor.from_row_starts(values, row_starts=[0, 4, 4, 7, 8]))\n",
        "print(tf.RaggedTensor.from_row_limits(values, row_limits=[4, 4, 7, 8, 8]))\n",
        "print(tf.RaggedTensor.from_value_rowids(\n",
        "    values, value_rowids=[0, 0, 0, 0, 2, 2, 2, 3], nrows=5))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZGRrpwxjsOGr"
      },
      "source": [
        "RaggedTensor 클래스는 이러한 각 행 분할 텐서를 생성하는데 사용할 수 있는\n",
        "메서드를 정의합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fIdn-hUBsoSj"
      },
      "outputs": [],
      "source": [
        "rt = tf.ragged.constant([[3, 1, 4, 1], [], [5, 9, 2], [6], []])\n",
        "print(\"      values: {}\".format(rt.values))\n",
        "print(\"  row_splits: {}\".format(rt.row_splits))\n",
        "print(\" row_lengths: {}\".format(rt.row_lengths()))\n",
        "print(\"  row_starts: {}\".format(rt.row_starts()))\n",
        "print(\"  row_limits: {}\".format(rt.row_limits()))\n",
        "print(\"value_rowids: {}\".format(rt.value_rowids()))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2r9XUpLUsdOa"
      },
      "source": [
        "(`tf.RaggedTensor.values`와 `tf.RaggedTensors.row_splits`는 프로퍼티이며, 나머지 행 분할 접근자는 모두 메서드입니다. 이는 `row_splits`가 기본 표현이고 다른 행 분할 텐서는 계산되어야함을 나타냅니다.)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NBX15kEr-PWi"
      },
      "source": [
        "서로 다른 행 분할 방식의 장점과 단점은\n",
        "다음과 같습니다:\n",
        "\n",
        "+ **효율적인 인덱싱**:\n",
        "    `row_splits`, `row_starts` 및 `row_limits` 방식은 모두 비정형 텐서에\n",
        "    일정한 시간 인덱싱을 가능하게 합니다. `value_rowids`와\n",
        "     `row_lengths` 방식은 가능하지 않습니다.\n",
        "\n",
        "+ **작은 인코딩 크기**:\n",
        "    텐서의 크기는 값의 총 수에만 의존하기 때문에 빈 행이 많은 비정형 텐서를 저장할 때 `value_rowids`\n",
        "    방식이 더 효율적입니다.\n",
        "    반면, 다른 4개의 인코딩은 각 행에 대해 하나의 스칼라 값만 필요하므로\n",
        "    행이 긴 비정형 텐서를\n",
        "    저장할 때 더 효율적입니다.\n",
        "\n",
        "+ **효율적인 연결**:\n",
        "   두 개의 텐서가 함께 연결될 때 행 길이가 변경되지 않으므로\n",
        "   (행 분할 및 행 인덱스는 변경되므로)\n",
        "   비정형 텐서를 연결할 때 `row_lengths` 방식이 더 효율적입니다.\n",
        "\n",
        "+ **호환성**:\n",
        "    `value_rowids` 방식은 `tf.segment_sum`과 같은 연산에서 사용되는\n",
        "    [분할](../api_guides/python/math_ops.md#Segmentation)\n",
        "    형식과 일치합니다. `row_limits` 방식은\n",
        "    `tf.sequence_mask`와 같이 작업에서 사용하는 형식과 일치합니다."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "ragged_tensor.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
